//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using OpenLS.Drawing;
using OpenLS.Drawing.UI.Internals;

namespace OpenLS.Chart.UI
{
    class Area3DModelFactory: IMultiValueConverter
    {
        #region IMultiValueConverter Members

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var series = StrictConverter.Convert<ObservableCollection<AreaSeries>>(values[0]);
            if (series == null)
                return null;
            var colorScheme = StrictConverter.Convert<ColorScheme>( values[1]);
            var style = StrictConverter.Convert<ChartStyle>(values[2]);
            var grouping = (Grouping)values[3];
            try
            {
                return createModelGroup(series, colorScheme, style, grouping);
            }
            catch{
                return null;}
        }

        private static object createModelGroup(ObservableCollection<AreaSeries> series, ColorScheme colorScheme, ChartStyle style, Grouping grouping)
        {
            var result = new Model3DGroup();
            int seriesIndex = -1;
            ChartLayout layout = ChartToChartInfoConverter.GetLayout(grouping, series);
            foreach (AreaSeries currentSeries in series)
            {
                seriesIndex++;
                Brush brush;
                if (currentSeries.ShapeProperties != null && currentSeries.ShapeProperties.FillProperties != null)
                    brush =
                        FillPropertiesToBrushConverter.FillPropertiesToBrush(currentSeries.ShapeProperties.FillProperties,
                                                                             colorScheme, null); //\\
                else
                    brush = PatternConverter.GetBrush(style, seriesIndex, colorScheme);
                double seriesZ = layout.GetZ(currentSeries.Index);
                var geometry = new MeshGeometry3D();
                var modelGroup = new Model3DGroup();
                NumericValue previousValue = null;
                Bounds? previousBounds1 = null;
                foreach (NumericValue value in currentSeries.Values.Values)
                {
                    if (previousBounds1 != null)
                    {
                        Bounds currentBounds = layout.GetBounds(value, currentSeries, 0);
                        Bounds previousBounds = previousBounds1.Value;
                        Tessellator.Tessellate(
                            geometry,
                                             new[]
                                                 {
                                                     new Point3D(previousValue.Index, previousBounds.High, -seriesZ),
                                                     new Point3D(value.Index, currentBounds.High, -seriesZ),
                                                     new Point3D(value.Index, currentBounds.High, -seriesZ - 1),
                                                     new Point3D(previousValue.Index, previousBounds.High, -seriesZ - 1)
                                                 });
                        Tessellator.Tessellate(geometry,
                                             new Vector3D(0, 0, 1),
                                             new[]
                                                                        {
                                                                            new Point3D(previousValue.Index, previousBounds.Low, -seriesZ),
                                                                            new Point3D(value.Index, currentBounds.Low, -seriesZ),
                                                                            new Point3D(value.Index, currentBounds.High, -seriesZ),
                                                                            new Point3D(previousValue.Index, previousBounds.High, -seriesZ)
                                                                        });
                        Tessellator.Tessellate(geometry,
                                             new Vector3D(0, 0, -1),
                                             new[]
                                    {
                                                                             new Point3D(previousValue.Index, previousBounds.High, -seriesZ-1),
                                                                             new Point3D(value.Index, currentBounds.High, -seriesZ-1),
                                                                             new Point3D(value.Index, currentBounds.Low, -seriesZ-1),
                                                                             new Point3D(previousValue.Index, previousBounds.Low, -seriesZ-1),
                                    });
                        previousBounds1 = currentBounds;
                    }
                    else
                    {
                        Bounds currentBounds = layout.GetBounds(value, currentSeries, 0);
                        Tessellator.Tessellate(geometry,
                                             new Vector3D(-1, 0, 0), new[]
                                                                         {
                                                                             new Point3D(value.Index, currentBounds.Low, -seriesZ),
                                                                             new Point3D(value.Index, currentBounds.High, -seriesZ),
                                                                             new Point3D(value.Index, currentBounds.High, -seriesZ-1),
                                                                             new Point3D(value.Index, currentBounds.Low, -seriesZ-1),
                                                                         });
                        previousBounds1 = layout.GetBounds(value, currentSeries, 0);
                    }
                    previousValue = value;
                }
                if (previousValue != null)
                {
                    Bounds bounds = layout.GetBounds(previousValue, currentSeries, 0);
                    Tessellator.Tessellate(geometry,
                                         new Vector3D(1, 0, 0), new[]
                                                                    {
                                                                        new Point3D(previousValue.Index, bounds.Low, -seriesZ),
                                                                        new Point3D(previousValue.Index, bounds.Low, -seriesZ-1),
                                                                        new Point3D(previousValue.Index, bounds.High, -seriesZ-1),
                                                                        new Point3D(previousValue.Index, bounds.High, -seriesZ),
                                                                    });
                }
                var mesh = new GeometryModel3D(geometry, new DiffuseMaterial(brush));
                                    modelGroup.Children.Add(mesh);
                                    SeriesElement.SetSeries(mesh, currentSeries);
                                    ChartElement.SetObjectContext(mesh, currentSeries);
                                    result.Children.Add(modelGroup);

            }
            return result;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }

        #endregion
    }
}
